﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.ServiceModel.Syndication;
using System.Xml;

namespace $safeprojectname$.Model
{
    public abstract class ItemMapper : IObservable<RssItem>
    {
        private IList<IObserver<RssItem>> _observers = new List<IObserver<RssItem>>();
        private string _feed;

        public ItemMapper(string rssFeed)
        {
            _feed = rssFeed;
        }

        public void Start()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += ParseFeed;
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(FeedParsed);
            worker.RunWorkerAsync(new WorkerData(this,_feed));
        }

        void FeedParsed(object sender, RunWorkerCompletedEventArgs e)
        {
            foreach (var observer in _observers)
            {
                observer.OnCompleted();
            }
        }

        private class WorkerData
        {
            private ItemMapper _mapper;

            public ItemMapper Mapper
            {
                get { return _mapper; }
            }

            private string _feed;

            public string Feed
            {
                get { return _feed; }
            }

            public WorkerData(ItemMapper mapper, string feed)
            {
                _mapper = mapper;
                _feed = feed;
            }
        }

        private void ParseFeed(object sender, DoWorkEventArgs e)
        {
            WorkerData data = e.Argument as WorkerData;
            ParseFeed(data.Mapper, data.Feed);
        }

        private void ParseFeed(ItemMapper mapper, string rssFeed)
        {
            StringReader str = new StringReader(rssFeed);
            XmlReader reader = XmlReader.Create(str);
            SyndicationFeed feed = SyndicationFeed.Load(reader);
            foreach (var item in feed.Items)
            {
                RssItem rssItem = MapItem(item);
                mapper.NotifyObservers(rssItem);
            }
        }

        private void NotifyObservers(RssItem rssItem)
        {
            foreach (var observer in _observers)
            {
                observer.OnNext(rssItem);
            }
        }

        public abstract RssItem MapItem(SyndicationItem item);

        public IDisposable Subscribe(IObserver<RssItem> observer)
        {
            _observers.Add(observer);
            return new EndObserving(_observers, observer);
        }

        private class EndObserving : IDisposable
        {
            public EndObserving(IList<IObserver<RssItem>> observers, IObserver<RssItem> observer)
            {
                _observers = observers;
                _observer = observer;
            }

            private IList<IObserver<RssItem>> _observers = new List<IObserver<RssItem>>();
            private IObserver<RssItem> _observer;
            public void Dispose()
            {
                _observers.Remove(_observer);
                _observer = null;
                _observers = null;
            }
        }
    }
}
